// ==============业务逻辑代码==========================
// 初始化websocket
// 显示本地视频 并且加入房间
/* 定义变量 */
// 用户名

//这个必须要 localhost, 0.0.0.0 不行;
// var roomid = getQueryString('room');
// var userName = getQueryString('name');
// if (!roomid || !userName) {
//   // roomId = document.getElementById('roomid');
//   // userName= document.getElementById('username');
//   alert('检测url上无房间号或者无用户名，并赋予默认值！');
//   window.location.href = window.location.protocol + '//' + window.location.host + `?room=${roomid || '10'}&name=${userName || 'aaa'}`
// }

var roomid = null;
var userName = null;
// websocket 实例
chatSocket = null;
// 获取摄像头和音频配置
mediaConstraints = { "audio": true, "video": true };
// 视频盒子
videoBox = document.getElementById('videoBox');
// 本地视频对象

// 文本消息盒子
textBox = document.getElementById('textBox');

// 本地流
var localStream = null;
// 存储用户对象
peerList = {};

websocketInit();//网页加载时运行;

function getUserMedia() {
  console.log("into  getUserMedia");
  try {
    // localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
    if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
      console.log('getUserMedia is not supported');
    }
    var mediaConstraints = { "audio": true, "video": true };

    var localV = document.getElementById('localVideo');
    console.log('getlocalstream');
    navigator.mediaDevices.getDisplayMedia(mediaConstraints).then((mediastream00) => {
      localV.srcObject = mediastream00;
      window.localStream = mediastream00;
      roomid = document.getElementById('roomid').value;
      userName = document.getElementById('username').value;
      if(roomid==null|userName==null){
        console.alert(姓名和id不能为空);
      }
      sendMessage({
        roomid: roomid,
        myName: userName,
        type: 'join'
      });

    }).catch(err => {
      console.log('获取本地摄像头失败：' + err);
    });
}catch(err){
  console.log('获取本地摄像头失败：' + err);
};
}

// =================websocket====================

function websocketInit() {
  console.log("into websocketInit");
  try {
    // 浏览器提供 WebSocket 对象
    //注意这里必须是ws://localhost:3000
    //不能是 ws://0.0.0.0:3000
    // https://0.0.0.0:3000
    
    chatSocket = new ReconnectingWebSocket('wss://192.168.2.35:3000');
  } catch (error) {
    console.log('发生错误：' + error);
  }

  // 监听消息
  chatSocket.onmessage = function (evt) {
    var msg = JSON.parse(evt.data);
    switch (msg.type) {
      // var msgString = {
      //   type: 'joined',
      //   roomid: rid,
      //   userList: roomInfo[rid].names,
      //   userName: uname
      // };
      case "joined":
        console.log("userjoined");
        userJoined(msg.userList, msg.userName);// 所有成员, 新加入的user

        var p = document.createElement('p');
        p.innerText = msg.userName + ' 加入了房间';
        p.className = 'p-hint';
        textBox.append(p);
        break;
      // var msgString = {
      //   type: '__ice_candidate',
      //   candidate: msg.candidate,
      //   roomid : msg.roomid,
      //   receiver:msg.opponame,
      //   account: msg.account,
      //   sender: msg.userName
      // };

      case "__ice_candidate":
        console.log("__ice_candidate");
        //如果是一个ICE的候选，则将其加入到PeerConnection中
        if (msg.candidate) {
          peerList[msg.account] && peerList[msg.account].addIceCandidate(msg.candidate).catch(() => { });
          //这个其实时表示判断&&前面的结果然后计算后面的表达式;
          console.log("end __ice_candidate");
        }
        break;
      case "error":
        alert(msg.msg);
        break;
      case "text":
        console.log("text");
        var p = document.createElement('p');
        p.innerText = msg.userName + ': ' + msg.text;
        textBox.append(p);
        break;
      // 信令消息:这些消息用于在视频通话之前的谈判期间交换WebRTC信令信息。
      // var msgString = {
      //   type: "video-offer",
      //   roomid : msg.roomid,
      //   sdp: msg.sdp,
      //   receiver: msg.account
      // account:p2paccount
      // };
      case "video-offer":  // 发送 offer
        console.log("video-offer");
        // createanwser(p2paccount,accountname, peer,remotedes);
        createanwser(msg);
        break;
      // var msgString = {
      //   type: "video-answer",
      //   roomid: msg.roomid,
      //   sender :msg.sender,
      //   receiver:msg.receiver,
      //   sdp: msg.sdp,
      //   p2paccount: msg.p2paccount
      case "video-answer":  // Callee已经答复了我们的报价
        console.log("video-answer");

        // createOfferandanswer(p2p.account,sender, peerList[p2p.account]);
        peerList[msg.p2paccount] && peerList[msg.p2paccount].setRemoteDescription(msg.sdp).catch(function () { });
        break;
      case "disconnected": // 有人挂断了电话
        console.log("disconnected");
        console.log(msg.account);
        let dom = document.querySelector('#' + [msg.account, userName].sort().join('-'));
        if (dom) {
          dom.remove();
          var p = document.createElement('p');
          p.innerText = msg.account + ' 退出了房间';
          p.className = 'p-hint';
          textBox.append(p);
        }
        break;
      // 未知的信息;输出到控制台进行调试。
      default:
        console.log("未知的信息收到了:");
        console.log(msg);
    }
  };
  //连接成功建立的回调方法
  chatSocket.onopen = function () {
    console.log("onopen");
  }
  //连接关闭的回调方法
  chatSocket.onclose = function () {
    // chatSocket.close();
    console.log("websocket.onclose");
  }
  //连接发生错误的回调方法
  chatSocket.onerror = function () {
    // chatSocket.close();
    console.log("chatSocket.error");
  };
  window.onbeforeunload = function () {
    // chatSocket.close();
  }
}
// 监听用户加入 ,
function userJoined(userlist, sender) {
  console.log("into userjoined");
    console.log(userlist);
  // 这里表示接受到的这个joined是自己;需要针对收到的userlist创建对应的peer和offer就行;
  //因为userlist 包含这个房间里所有的users ,sender等于自己时,就像所有的users发送音视频,如果sender不是自己,那么自己就是个接收者,就不需要接下来的主动发送操作;
  if (sender == userName) {
    if (userlist.length > 1) {
      userlist.forEach(useropponent => {
        let p2p = {};
        let arr = [useropponent, userName];
        p2p.account = arr.sort().join('-');//foreach每次都改写obj的account成员;
        if (!peerList[p2p.account] && useropponent !== userName) {  //peerlist是个map,查看这个map是否有这个通信对;如果没有说明这个通信对是新加入的;
          getPeerConnection(p2p.account, useropponent);//针对每一个通话端口都会调用本函数;
          //上面的调用会产生一个 peerList[p2p.account];
          console.log("======="+useropponent);
          createOffer(p2p.account, useropponent, peerList[p2p.account]);
        }
      });
      // 当房间有人存在则向房间其它人发offeraccount
      // if (sender != userName) {
      //   // console.log('account', account);
      //   for (let k in peerList) {
      //     createOffer(sender, peerList[k]);
      //   }
      // }
    }
  }
  //这里表示新加入了一个用户;joined的用户不是自己;只创建一个peer和offer就行;

}
// 发送消息
function sendMessage(msg) {
  console.log("sendmessage : "+ msg);
  msg.roomid = roomid;
  chatSocket.send(JSON.stringify(msg));
}


// =============================webRTC===================

// 创建 RTCPeerConnection
function getPeerConnection(p2p, oppo) {
  console.log('getPeerConnection');
  let iceServer = {
    "iceServers": [
      // {
      //   "urls": ["stun:stun.l.google.com:19302"]

      // },
      // 需要把turnsever服务器的地址换成自己的
      {
        "urls": ["stun:192.168.2.22:3478"],
        username: "admin",
        credential: "123456",
      },
    ],
    sdpSemantics: 'unified-plan'
  };
  // 创建
  var peer = new RTCPeerConnection(iceServer);
 
  //向 RTCPeerConnection 中加入需要发送的流
  console.log("添加本地流" );
  peer.addStream(window.localStream);
  // 判断使用哪个方法监听流
  var hasAddTrack = (peer.addTrack !== undefined);  //peer是个RTCPeerConnection类对象,这个类不同版本有不同的方法,所以需要检测方法是否为 undifined;
  // 如果检测到媒体流连接到本地，将其绑定到一个video标签上输出
  if (hasAddTrack) {
    peer.ontrack = (event) => {
      console.log("添加远端流" );
      let videos = document.querySelector('#' + p2p);
      if (videos) {
        videos.srcObject = event.streams[0];
      } else {
        let video = document.createElement('video');
        video.controls = true;
        video.autoplay = 'autoplay';
        video.srcObject = event.streams[0];
        video.id = p2p;
        video.className = 'col-md-6';
        videoBox.append(video);
      }
    }
  } else {
    peer.onaddstream = (event) => {
      let videos = document.querySelector('#' + p2p);
      if (videos) {
        videos.srcObject = event.stream;
      } else {
        let video = document.createElement('video');
        video.controls = true;
        video.autoplay = 'autoplay';
        video.srcObject = event.stream;
        video.id = p2p;
        video.className = 'col-md-4';
        videoBox.append(video);
      }
    };
  }
  //发送ICE候选到其他客户端
  peer.onicecandidate = (event) => {
    var opponent = oppo;
    console.log("into peer.onicecandidate");

    if (event.candidate) {
     
      sendMessage({
        roomid: '10',
        type: '__ice_candidate',  //对应的Server,似乎没有写出来;
        candidate: event.candidate,
        opponame: opponent,

        account: p2p
      });
      
    }
  };
  
  peerList[p2p] = peer;  //添加map成员;
}
// createOffer
function createOffer(p2paccount, opponame, peer) {
  console.log("into createoffer");
  //发送offer，发送本地session描述
  peer.createOffer({
    offerToReceiveAudio: 1,
    offerToReceiveVideo: 1
  }).then((desc) => {
    peer.setLocalDescription(desc);
    descstr= JSON.stringify(desc);
    sendMessage({
      roomid: '10',
      type: 'video-offer',
      sdp: desc,
      sender: userName,
      receiver: opponame,
      account: p2paccount
    });
    console.log("receiver" + opponame);
  });
}

function createanwser(msg) {
  console.log("into createanswer" + msg);
  //peerlist是个map,查看这个map是否有这个通信对;如果没有说明这个通信对是新加入的;
  getPeerConnection(msg.p2paccount, msg.sender);//针对每一个通话端口都会调用本函数;
  //上面的调用会产生一个 peerList[p2p.account];
  peerList[msg.p2paccount].setRemoteDescription(msg.sdp)
    .then(() => peerList[msg.p2paccount].createAnswer({
      offerToReceiveAudio: 1,
      offerToReceiveVideo: 1
    }))
    .then((answer) => peerList[msg.p2paccount].setLocalDescription(answer))
    .then(() => {
      sendMessage({
        roomid: '10',
        type: 'video-answer',
        sdp: peerList[msg.p2paccount].localDescription,
        sender: userName,
        receiver: msg.sender,
        p2paccount: msg.p2paccount
      })
      // Send the answer to the remote peer using the signaling server
    })
    .catch(() => { });
}


// 收到offer请求
// function handleVideoOfferMsg(v) {
//   // peerList[v.account] && peerList[v.account].setRemoteDescription(v.sdp).then( () => {
//   //   peerList[v.account].createAnswer().then((desc) => {
//   //     // console.log('send-answer', desc);
//   //     peerList[v.account].setLocalDescription(desc);
//   //     sendMessage({
//   //       roomid : '10',
//   //       type: 'video-answer',
//   //       sdp: peerList[v.account].localDescription,
//   //       account: v.account
//   //     })
//   //   });
//   // });
// }




// ==============================其他方法==================
// 根据url 获取用户名和房间号创建多人视频聊天室 http://localhost:3001/?room=10&name=abc
function getQueryString(name) {
  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  var r = window.location.search.substr(1).match(reg);
  if (r != null) return unescape(r[2]);
  return null;
}

// 点击按钮发送消息
function sendTextMsg() {
  console.log("发送文本消息 " );
  // 提交文本消息按钮
  var textMsg = document.getElementById('textMsg');
  if (textMsg.value) {
    sendMessage({
      roomid: '10',
      type: 'text',
      userName: userName,
      text: textMsg.value
    });
    textMsg.value = '';
  }
}
// 键盘事件处理程序。这用于拦截返回和输入键，以便我们可以调用send()将输入的文本传输到服务器。
function handleKey(evt) {
  console.log("处理发送按键 " );
  if (evt.keyCode === 13 || evt.keyCode === 14) {
    sendTextMsg();
  }
}
